package study.translation.interpreter;

public class ComplexNumber implements Number
{
    private RealNumber re;

    private RealNumber im;

    public ComplexNumber( double re )
    {
        this( new RealNumber( re ) );
    }

    public ComplexNumber( double re, double im )
    {
        this( new RealNumber( re ), new RealNumber( im ) );
    }

    public ComplexNumber( RealNumber re )
    {
        this( re, new RealNumber( 0 ) );
    }

    public ComplexNumber( RealNumber re, RealNumber im )
    {
        this.re = re;
        this.im = im;
    }

    public RealNumber getRe()
    {
        return re;
    }

    public RealNumber getIm()
    {
        return im;
    }

    public Number add( Number n )
    {
        if( n instanceof ComplexNumber )
        {
            ComplexNumber c = ( ComplexNumber )n;
            return new ComplexNumber( ( RealNumber )getRe().add( c.getRe() ),
                                      ( RealNumber )getIm().add( c.getIm() ) );
        }
        else
        {
            return new ComplexNumber( ( RealNumber )getRe().add( n ), getIm() );
        }
    }

    public Number sub( Number n )
    {
        return add( n.changeSign() );
    }

    public Number mul( Number n )
    {
        if( n instanceof ComplexNumber )
        {
            ComplexNumber c = ( ComplexNumber )n;
            return new ComplexNumber( ( RealNumber )getRe().mul( c.getRe() ).sub( getIm().mul( c.getIm() ) ),
                                      ( RealNumber )getIm().mul( c.getRe() ).add( getRe().mul( c.getIm() ) ) );
        }
        else
        {
            return new ComplexNumber( ( RealNumber )getRe().mul( n ),
                                      ( RealNumber )getIm().mul( n ) );
        }
    }

    public Number div( Number n )
    {
        if( n instanceof ComplexNumber )
        {
            ComplexNumber c = ( ComplexNumber )n;
            RealNumber re = ( RealNumber )getRe().mul( c.getRe() ).add( getIm().mul( c.getIm() ) )
                    .div( c.getRe().mul( c.getRe() ).add( c.getIm().mul( c.getIm() ) ) );
            RealNumber im = ( RealNumber )getIm().mul( c.getRe() ).sub( getRe().mul( c.getIm() ) )
                    .div( c.getRe().mul( c.getRe() ).add( c.getIm().mul( c.getIm() ) ) );
            return new ComplexNumber( re, im );
        }
        else
        {
            return new ComplexNumber( ( RealNumber )getRe().div( n ),
                                      ( RealNumber )getIm().div( n ) );
        }
    }

    public Number changeSign()
    {
        return mul( new RealNumber( -1 ) );
    }

    public boolean equals( Number n )
    {
        if( n instanceof ComplexNumber )
        {
            ComplexNumber c = ( ComplexNumber )n;
            return ( getRe().equals( c.getRe() ) && getIm().equals( c.getIm() ) );
        }
        else
        {
            return n.equals( this );
        }
    }

    public boolean greaterThan( Number n )
    {
        throw new RuntimeException( "Operation \"greater than\" cannot be applied to complex numbers!" );
    }

    public String toString()
    {
        if( im.getValue() == 0 )
        {
            return re.toString();
        }
        return ( im.getValue() > 0 )
               ? ( re + "+" + im + "i" )
               : ( re + "-" + im.changeSign() + "i" );
    }
}
